/*  This file is part of o.O.

    o.O is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    o.O is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with o.O.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2013 Oliver Katz */

#include "types.h"

using namespace std;

namespace oO
{
	Page::Page()
	{
	}

	Page &Page::read(string p)
	{
		ifstream f(p.c_str());
		if (!f.good())
			return *this;
		string tmp((istreambuf_iterator<char>(f)), istreambuf_iterator<char>());
		buf = tmp;
		return *this;
	}

	string &Page::buffer()
	{
		return buf;
	}

	string Page::getPath()
	{
		return path;
	}

	string Page::line(unsigned int n)
	{
		stringstream ss(buf);
		string l;
		int c = 0;
		while(getline(ss, l, '\n'))
			if (c++ >= n)
				break;
		return l;
	}

	PageLocation::PageLocation()
	{
		line = column = 0;
	}

	unsigned int PageLocation::getLine()
	{
		return line;
	}

	unsigned int PageLocation::getColumn()
	{
		return column;
	}

	string PageLocation::displayColor(Page p, string c)
	{
		stringstream ss;
		string l = p.line(line);
		ss << l.substr(0, column) << c << l[column] << "\033[0;0m" << l.substr(column+1);
		return ss.str();
	}

	string PageLocation::displayMultiline(Page p, string s)
	{
		stringstream ss;
		string l = p.line(line);

		int n = 0;
		for (n = 0; n < l.size() && l[n] == '\t'; n++);

		string pad(column-n, ' ');

		ss << l.substr(n) << "\n";
		ss << pad << s;
		return ss.str();
	}

	Token::Token()
	{
	}

	string Token::get()
	{
		return content;
	}

	Token::operator string ()
	{
		return content;
	}

	PageLocation Token::getLocation()
	{
		return location;
	}

	Token::operator PageLocation ()
	{
		return location;
	}

	AST::AST()
	{
	}

	AST &AST::adopt(AST c)
	{
		children.push_back(c);
		return *this;
	}

	AST &AST::operator << (AST c)
	{
		children.push_back(c);
		return *this;
	}

	string AST::getName()
	{
		return name;
	}

	Token &AST::operator [] (string c)
	{
		return content[c];
	}

	AST::iterator AST::begin()
	{
		return children.begin();
	}

	AST::iterator AST::end()
	{
		return children.end();
	}

	bool AST::leaf()
	{
		return (children.empty());
	}

	void AST::dump(string pref)
	{
		cout << pref << "'" << name << "'";
		if (!content.empty() || !children.empty())
			cout << ":\n";
		for (map<string, Token>::iterator i = content.begin(); i != content.end(); i++)
		{
			cout << " '" << i->first << "':'" << i->second.get() << "'";
		}
		if (!content.empty())
			cout << "\n";
		for (vector<AST>::iterator i = children.begin(); i != children.end(); i++)
		{
			i->dump(pref+"  ");
		}
		if (children.empty())
			cout << "\n";
	}

	void AST::dump()
	{
		dump("");
	}

	Error::Error()
	{
	}

	Error &Error::note(string n)
	{
		notes.push_back(n);
		return *this;
	}

	Error &Error::value(string n, string v)
	{
		svalues[n] = v;
		return *this;
	}

	Error &Error::value(string n, int v)
	{
		ivalues[n] = v;
		return *this;
	}

	void Error::dump()
	{
		cerr << page.getPath() << ":" << location.getLine() << location.displayColor(page, "\033[0;31m") << "\n";
		cerr << "  - " << msg << "\n";
		for (vector<string>::iterator i = notes.begin(); i != notes.end(); i++)
			cerr << "  - " << *i << "\n";
		for (map<string, string>::iterator i = svalues.begin(); i != svalues.end(); i++)
			cerr << "  - " << i->first << " <= \"" << i->second << "\"\n";
		for (map<string, int>::iterator i = ivalues.begin(); i != ivalues.end(); i++)
			cerr << "  - " << i->first << " <= " << i->second << "\n";
	}

	vector<Error> errorBuffer;

	void dumpAndDieIfErrors()
	{
		for (vector<Error>::iterator i = errorBuffer.begin(); i != errorBuffer.end(); i++)
			i->dump();
		if (!errorBuffer.empty())
			_exit(1);
	}
}

